#include "RowsShell.h"
#include "util.h"
#include <rapidjson/document.h>

using namespace std;
using namespace rapidjson;

RowsShell::RowsShell() : RowsShell({ }) { }

RowsShell::RowsShell(std::initializer_list<Row> rows) : Rows(rows) { }

std::string RowsShell::ToString() const
{
    auto dom = Document();
    dom.SetObject();
    auto rowShell = Document();
    rowShell.SetArray();
    for(const auto& i : Rows)
    {
        auto row = Document();
        row.SetObject();
        row.AddMember("key", Document().SetString(Base64Encode(i.Key).c_str(), dom.GetAllocator()), dom.GetAllocator());
        auto cells = Document();
        cells.SetArray();
        for (const auto &j : i.Cells)
        {
            auto cell = Document();
            cell.SetObject();
            cell.AddMember("column", Document().SetString(Base64Encode(j.column).c_str(), dom.GetAllocator()),
                           dom.GetAllocator());
            cell.AddMember("$", Document().SetString(Base64Encode(j.value).c_str(), dom.GetAllocator()),
                           dom.GetAllocator());
            if (j.withTimestamp)
                cell.AddMember("timestamp", j.timestamp, dom.GetAllocator());
            cells.PushBack(cell, dom.GetAllocator());
        }
        row.AddMember("Cell", cells, dom.GetAllocator());
        rowShell.PushBack(row, dom.GetAllocator());
    }
    dom.AddMember("Row", rowShell, dom.GetAllocator());
    return GetJsonString(dom);
}

bool RowsShell::FromString(const string &json)
{
    auto dom = Document();
    dom.Parse(json.c_str());
    if(dom.HasParseError())
        return false;
    if(!dom.HasMember("Row"))
        return false;
    if(!dom["Row"].IsArray())
        return false;
    auto rows = dom["Row"].GetArray();
    Rows.clear();
    for (auto i = rows.Begin(); i != rows.End(); i++)
    {
        if (!i->IsObject())
            return false;
        auto row = i->GetObject();
        if (!row.HasMember("key"))
            return false;
        if (!row.HasMember("Cell"))
            return false;
        if (!row["key"].IsString())
            return false;
        if (!row["Cell"].IsArray())
            return false;
        auto row_ = Row();
        row_.Key = Base64Decode(row["key"].GetString());
        auto cells = row["Cell"].GetArray();
        row_.Cells.clear();
        for (auto j = cells.Begin(); j != cells.End(); j++)
        {
            if (!j->HasMember("column"))
                return false;
            if (!j->HasMember("$"))
                return false;
            if (!(*j)["column"].IsString())
                return false;
            if (!(*j)["$"].IsString())
                return false;
            auto key = Base64Decode((*j)["column"].GetString());
            auto value = Base64Decode((*j)["$"].GetString());
            if (!j->HasMember("timestamp"))
            {
                row_.Cells.emplace_back(Cell(key, value));
                continue;
            }
            if (!(*j)["timestamp"].IsUint64())
                return false;
            uint64_t timestamp = (*j)["timestamp"].GetUint64();
            row_.Cells.emplace_back(Cell(key, value, timestamp));
        }
        Rows.emplace_back(row_);
    }
    return true;
}